/**
 * <pre>
 * @(#)MultiKeyedMapImpl.java 1.00 2009-11-9
 * 
 * Copyright (c) 1998, 2009 Regular Individual. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Contributor(s):
 *     Haixu Huang
 * </pre>
 **/
package cn.sh.huang.chart.ext.map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * <pre>
 * MultiKeyedMapImpl ...
 * 
 * @version 1.0
 * </pre>
 */
class MultiKeyedMapImpl implements MultiKeyedMap
{
    private final Map[] maps;

    MultiKeyedMapImpl(int keyCount)
    {
        if (keyCount < 1) {
            throw new IllegalArgumentException();
        }
        maps = new Map[keyCount];
        for (int i = 0; i < keyCount; i++) {
            maps[i] = new HashMap();
        }
    }

    /*
     * (non-Javadoc)
     * @see multimap.MultiKeyedMap#containsKey(int, java.lang.Object)
     */
    public boolean containsKey(int keyIndex, Object key)
    {
        return keyIndex >= maps.length ? false : maps[keyIndex].containsKey(key);
    }

    /*
     * (non-Javadoc)
     * @see multimap.MultiKeyedMap#get(java.lang.Object[])
     */
    public MultiKeyedEntry[] get(Object[] keys)
    {
        validateKeyCount(keys);
        Collection c = null;
        for (int i = 0; i < maps.length; i++) {
            Object key = keys[i];
            if (key != null) {
                Set valueSet = (Set) maps[i].get(key);
                if (valueSet == null) {
                    return new MultiKeyedEntry[0];
                }
                if (c == null) {
                    c = new LinkedHashSet(valueSet);
                } else {
                    c.retainAll(valueSet);
                    if (c.size() == 0) {
                        return new MultiKeyedEntry[0];
                    }
                }
            }
        }
        if (c == null) {
            c = new LinkedHashSet();
            Collection v = maps[0].values();

            for (Iterator it = v.iterator(); it.hasNext();) {
                c.addAll((Set) it.next());
            }
        }
        return (MultiKeyedEntry[]) c.toArray(new MultiKeyedEntry[c.size()]);
    }

    /*
     * (non-Javadoc)
     * @see multimap.MultiKeyedMap#put(java.lang.Object[], java.lang.Object)
     */
    public void put(Comparable[] keys, Object value)
    {
        validateKeyCount(keys);
        MultiKeyedEntry entry = new MultiKeyedEntry(keys);
        entry.setValue(value);
        for (int i = 0; i < maps.length; i++) {
            if (keys[i] == null) {
                throw new IllegalArgumentException();
            }
            Set set = (Set) maps[i].get(keys[i]);
            if (set == null) {
                set = new TreeSet();
                maps[i].put(keys[i], set);
            }
            set.add(entry);
        }
    }

    private void validateKeyCount(Object[] keys)
    {
        if (keys.length != maps.length) {
            throw new IllegalArgumentException();
        }
    }
}
